#pragma once
using std::cout;
using std::endl;

template <class T>
class ObjectPool
{
public:
    T *New()
    {
        T *obj;
        // 优先考虑使用_free_list内的内存块
        if (_free_list)
        {
            void* next = *((void**)_free_list);
            obj = (T*)_free_list;
            _free_list = next;
        }
        else
        {
            if (_remain_memory < sizeof(T)) // 剩余空间小于一个T类型大小时，就申请内存
            {
                _remain_memory = 128*1024;
                _memory = (char*)malloc(_remain_memory);
                if (!_memory)
                {
                    std::cout << "malloc error" << std::endl; 
                    exit(-1);
                }
            }
            obj = (T *)_memory;
            // 给的空间大小一定大于等于一个指针的大小
            size_t objsize = sizeof(T) < sizeof(void*) ? sizeof(void*) : sizeof(T);
            _memory += objsize;
            _remain_memory -= objsize;
        }

        new(obj)T; // 显示调用T类型的构造初始化obj

        return obj;
    }

    void Delete(T* obj)
    {
        // 还回来就是将内存块插入_free_list
        obj->~T(); // 显示调用T类型的析构
        // 直接头插，插入_free_list
        *(void**)obj = _free_list;
        _free_list = (void*)obj;
    }

private:
    char *_memory = nullptr; // 提前申请的大块内存地址
    void *_free_list = nullptr; // 还回来的内存块链表的头节点
    size_t _remain_memory = 0; // 大块内存剩余大小的字节数
};

////////////////////////////////////////////////////////////////////
// 测试代码

// struct TreeNode
// {
// 	int _val;
// 	TreeNode* _left;
// 	TreeNode* _right;

// 	TreeNode()
// 		:_val(0)
// 		, _left(nullptr)
// 		, _right(nullptr)
// 	{}
// };

// void TestObjectPool()
// {
// 	// 申请释放的轮次
// 	const size_t Rounds = 5;

// 	// 每轮申请释放多少次
// 	const size_t N = 100000;

// 	std::vector<TreeNode*> v1;
// 	v1.reserve(N);

// 	size_t begin1 = clock();
// 	for (size_t j = 0; j < Rounds; ++j)
// 	{
// 		for (int i = 0; i < N; ++i)
// 		{
// 			v1.push_back(new TreeNode);
// 		}
// 		for (int i = 0; i < N; ++i)
// 		{
// 			delete v1[i];
// 		}
// 		v1.clear();
// 	}

// 	size_t end1 = clock();

// 	std::vector<TreeNode*> v2;
// 	v2.reserve(N);

// 	ObjectPool<TreeNode> TNPool;
// 	size_t begin2 = clock();
// 	for (size_t j = 0; j < Rounds; ++j)
// 	{
// 		for (int i = 0; i < N; ++i)
// 		{
// 			v2.push_back(TNPool.New());
// 		}
// 		for (int i = 0; i < N; ++i)
// 		{
// 			TNPool.Delete(v2[i]);
// 		}
// 		v2.clear();
// 	}
// 	size_t end2 = clock();

// 	cout << "new cost time:" << end1 - begin1 << endl;
// 	cout << "object pool cost time:" << end2 - begin2 << endl;
// }